﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading.Tasks;

using System.IO;
using System.Reflection;
using System.Text;
using System.CodeDom.Compiler;
using Microsoft.CSharp;

namespace Excuter
{
    static class Program
    {
        public static bool isDebug = false;
        public static int delayMillionSecond = 0;

        public static string sourceCode = "";
        public static object[] sourceArgs = null;

        public static bool autoDelet = false;

        /// <summary>
        /// 应用程序的主入口点。可直接传入源码、或源码文件路径。DEBUG标识是否输出运行信息。DELAY标识延时毫秒时间值。AUTODELET是否自删除。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Form1());

            //if (args == null || args.Length == 0) args = new string[] { @"F:\sc\桌面快捷存储\tmp\Test.cs" };
            //string source = @"D:\sci\Visual Studio 2008\Projects\ClearDir\ClearDir\Resources\ClearTool.txt";
            //string source = @"D:\sci\Visual Studio 2008\Projects\ClearDir\ClearDir\bin\Debug\Code.txt";
            //if (args == null || args.Length == 0) args = new string[] { source, @"F:\sc\桌面快捷存储\tmp\新建文本文档.txt" };

            //if (args == null || args.Length == 0) args = new string[] { @"D:\sci\Visual Studio 2008\Projects\Excuter\Excuter\bin\Debug\Test.cs" };
            if (args !=null && args.Length > 0)
            {
                // 判断参数中是否含有DEBUG
                List<string> arglist = new List<string>();
                foreach (string arg in args)
                {
                    if (arg.Equals("DEBUG")) isDebug = true;
                    else if (arg.Equals("AUTODELET")) autoDelet = true;
                    else if (arg.StartsWith("DELAY")) delayMillionSecond = int.Parse(arg.Substring("DELAY".Length));
                    else arglist.Add(arg);
                }
                args = arglist.ToArray();

                // 其他参数作为执行参数
                string[] Arg = null;
                if (args.Length > 1)
                {
                    Arg = new string[args.Length - 1];
                    for (int i = 1; i < args.Length; i++)
                    {
                        Arg[i - 1] = args[i];
                    }
                }

                sourceCode = args[0];
                if(Arg != null) sourceArgs = new object[] { Arg };

                ExcuteProcess();                // 执行逻辑
                Application.Run();              // 在当前线程上运行应用程序消息循环
            }
            else if (autoDelet) AutoDelet.deletItself();
        }

        /// <summary>
        /// 根据param中的参数控制截屏
        /// </summary>
        public static void ExcuteProcess()
        {
            if (delayMillionSecond > 0)
            {
                Timer timer = new Timer();
                timer.Interval = delayMillionSecond;
                timer.Tick += Timer_Tick;

                delayMillionSecond = 0;
                timer.Enabled = true;
            }
            else
            {
                // 第一个参数作为源码或源码文件
                object result = "";
                if (File.Exists(sourceCode)) result = Excute.RunFileFirst(sourceCode, sourceArgs);
                else result = Excute.RunSourceCodeFirst(sourceCode, sourceArgs);

                if (isDebug && result != null) MessageBox.Show(sourceCode + "\r\n" + result.ToString());
                if (autoDelet) AutoDelet.deletItself();
                exit();
            }
        }

        /// <summary>
        /// 延时截屏处理逻辑
        /// </summary>
        private static void Timer_Tick(object sender, EventArgs e)
        {
            ((Timer)sender).Stop(); // 停止计时
            ExcuteProcess();        // 执行逻辑
        }

        /// <summary>
        /// 调用系统退出
        /// </summary>
        public static void exit()
        {
            //Application.Exit();
            //Application.ExitThread();
            System.Environment.Exit(0);
        }
    }



    /// <summary>
    /// 动态编译执行
    /// </summary>
    public class Excute
    {

        # region 动态编译源码并执行

        /// <summary>
        /// 解析并编译执行源码文件sourceFile，第一个类的首个公用或静态方法
        /// </summary>
        public static object RunFileFirst(string sourceFile, object[] args = null)
        {
            try
            {
                string sourceCode = fileToString(sourceFile);   // 读取文件内容
                return RunSourceCodeFirst(sourceCode, args);    // 执行
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }
        }

        /// <summary>
        /// 解析并编译执行sourceCode，第一个类的首个公用或静态方法
        /// </summary>
        public static object RunSourceCodeFirst(string sourceCode, object[] args = null)
        {
            try
            {
                sourceCode =  Encoder.Decode(sourceCode);                       // 解析源码
                string[] assemblies = getUsing(sourceCode).ToArray();           // 获取引用程序集
                string methodName = getFirstPublicMethod(sourceCode);           // 获取方法名
                bool isStatic = isPublicStaticMethod(sourceCode, methodName);   // 判断是否为静态方法

                return Run(sourceCode, "", methodName, args, isStatic, assemblies);    // 执行
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }
        }


        /// <summary>
        /// 动态编译执行
        /// </summary>
        /// <param name="sourceCode">源码</param>
        /// <param name="classFullName">命名空间.类</param>
        /// <param name="methodName">方法名</param>
        /// <param name="args">方法参数</param>
        /// <param name="assemblies">引用程序集</param>
        /// <param name="isStaticMethod">是否为静态方法</param>
        static object Run(string sourceCode, string classFullName, string methodName, object[] args = null, bool isStaticMethod = false, string[] assemblies = null)
        {
            try
            {
                // 设置编译参数 System.Xml.dll
                CompilerParameters param = new CompilerParameters();
                param.GenerateExecutable = false;
                param.GenerateInMemory = true;

                // 添加常用的默认程序集
                param.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
                param.ReferencedAssemblies.Add("mscorlib.dll");
                param.ReferencedAssemblies.Add("System.dll");
                param.ReferencedAssemblies.Add("System.Core.dll");
                param.ReferencedAssemblies.Add("System.Data.dll");
                param.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
                param.ReferencedAssemblies.Add("System.Drawing.dll");
                param.ReferencedAssemblies.Add("System.Windows.Forms.dll");
                param.ReferencedAssemblies.Add("System.Xml.dll");
                param.ReferencedAssemblies.Add("System.Xml.Linq.dll");

                if (assemblies != null)
                {
                    foreach (string name in assemblies)
                    {
                        string assembly = name + ".dll";
                        if (!param.ReferencedAssemblies.Contains(assembly))
                        {
                            param.ReferencedAssemblies.Add(assembly);
                        }
                    }
                }

                // 动态编译字符串代码
                CompilerResults result = new CSharpCodeProvider().CompileAssemblyFromSource(param, sourceCode);

                if (result.Errors.HasErrors)
                {
                    // 编译出错：
                    StringBuilder str = new StringBuilder();
                    foreach (CompilerError err in result.Errors)
                    {
                        str.AppendLine(err.ErrorText);
                    }
                    return str.ToString();
                }
                else
                {
                    // 编译通过：
                    Assembly assembly = result.CompiledAssembly;                // 获取已编译通过的程序集
                    if (classFullName == null || classFullName.Equals(""))      // 若未指定，则获取程序集第一个类路径名
                    {
                        classFullName = assembly.GetTypes()[0].FullName;
                    }

                    if (isStaticMethod)
                    {
                        // 调用程序集的静态方法： Type.InvokeMember
                        Type type = assembly.GetType(classFullName, true, true);

                        //object[] arg = new object[] { "参数1", "参数2" };
                        object tmp = type.InvokeMember(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, args);
                        return tmp;
                    }
                    else
                    {
                        // 调用程序集类实例方法： method.Invoke
                        object obj = assembly.CreateInstance(classFullName);    // 创建一个类实例对象
                        MethodInfo method = obj.GetType().GetMethod(methodName);// 获取对象的对应方法

                        object tmp = method.Invoke(obj, args);                  // 调用对象的方法
                        return tmp;
                    }
                }
            }
            catch (Exception ex) 
            { 
                return ex.ToString(); 
            }
        }

        # endregion

        # region 相关功能函数

        /// <summary>
        /// 获取文件中的数据,自动判定编码格式
        /// </summary>
        private static string fileToString(String filePath)
        {
            string str = "";

            //获取文件内容
            if (File.Exists(filePath))
            {
                StreamReader file1;

                file1 = new StreamReader(filePath, Encoding.UTF8);  // 读取文件中的数据
                str = file1.ReadToEnd();                            // 读取文件中的全部数据

                file1.Close();
                file1.Dispose();
            }
            return str;
        }

        /// <summary>
        /// 获取第一个公用方法
        /// </summary>
        /// <param name="sourceCode"></param>
        /// <returns></returns>
        private static string getFirstPublicMethod(string sourceCode)
        {
            string methodName = "";
            String[] lines = sourceCode.Replace("\r\n", "\n").Split('\n');
            foreach (string iteam in lines)
            {
                string line = iteam.Trim();
                if (line.StartsWith("public ") && line.Contains("(") && line.Contains(")"))
                {
                    methodName = line.Substring(0, line.IndexOf("("));
                    methodName = methodName.Substring(methodName.LastIndexOf(" ") + 1);
                    break;
                }
            }
            return methodName;
        }

        /// <summary>
        /// 判断指定的方法是否为静态方法
        /// </summary>
        /// <returns></returns>
        private static bool isPublicStaticMethod(string sourceCode, string methodName)
        {
            bool isStatic = false;
            String[] lines = sourceCode.Replace("\r\n", "\n").Split('\n');
            foreach (string iteam in lines)
            {
                string line = iteam.Trim();
                if (line.StartsWith("public ") && line.Contains(" " + methodName) && line.Contains("(") && line.Contains(")") && line.Contains("static"))
                {
                    isStatic = true;
                }
            }
            return isStatic;
        }

        /// <summary>
        /// 获取应用的程序集信息
        /// </summary>
        private static List<string> getUsing(string sourceCode)
        {
            String[] lines = sourceCode.Replace("\r\n", "\n").Split('\n');
            List<string> usings = new List<string>();
            foreach (string iteam in lines)
            {
                string line = iteam.Trim();
                if (line.StartsWith("using ") && line.EndsWith(";"))
                {
                    string usingAssembley = line.TrimEnd(';').Substring("using ".Length);
                    CheckAddAssembly(usings, usingAssembley);
                }
            }
            return usings;
        }

        /// <summary>
        /// 检测添加较短长度的Assembly名称
        /// </summary>
        private static void CheckAddAssembly(List<string> usings, string usingAssembley)
        {
            if (usings.Contains(usingAssembley)) return;
            for (int i = 0; i < usings.Count; i++)
            {
                string name = usings[i];
                if (usingAssembley.StartsWith(name + ".")) return;
                else if (name.StartsWith(usingAssembley + "."))
                {
                    usings[i] = usingAssembley;
                }
            }
            usings.Add(usingAssembley);
        }

        # endregion

    }

    public class Encoder
    {

        public static void example()
        {
            String data = "test encode";
            string encode = Encode(data);
            string decode = Decode(encode);
            bool b = data.Equals(decode);
            bool b2 = b;
        }

        /// <summary>
        /// 转码data为全字母串，并添加前缀
        /// </summary>
        public static string Encode(string data)
        {
            string str = data;
            if (!data.StartsWith("ALPHABETCODE@"))
            {
                str = "ALPHABETCODE@" + EncodeAlphabet(data);
            }
            return str;
        }


        /// <summary>
        /// 解析字母串为原有串
        /// </summary>
        public static string Decode(string data)
        {
            string str = data;
            if (data.StartsWith("ALPHABETCODE@"))
            {
                str = DecodeAlphabet(data.Substring("ALPHABETCODE@".Length));
            }
            return str;
        }


        # region 字符串字母编码逻辑

        /// <summary>
        /// 转化为字母字符串
        /// </summary>
        public static string EncodeAlphabet(string data)
        {
            byte[] B = Encoding.UTF8.GetBytes(data);
            return ToStr(B);
        }

        /// <summary>
        /// 每个字节转化为两个字母
        /// </summary>
        private static string ToStr(byte[] B)
        {
            StringBuilder Str = new StringBuilder();
            foreach (byte b in B)
            {
                Str.Append(ToStr(b));
            }
            return Str.ToString();
        }

        private static string ToStr(byte b)
        {
            return "" + ToChar(b / 16) + ToChar(b % 16);
        }

        private static char ToChar(int n)
        {
            return (char)('a' + n);
        }

        /// <summary>
        /// 解析字母字符串
        /// </summary>
        public static string DecodeAlphabet(string data)
        {
            byte[] B = new byte[data.Length / 2];
            char[] C = data.ToCharArray();

            for (int i = 0; i < C.Length; i += 2)
            {
                byte b = ToByte(C[i], C[i + 1]);
                B[i / 2] = b;
            }

            return Encoding.UTF8.GetString(B);
        }

        /// <summary>
        /// 每两个字母还原为一个字节
        /// </summary>
        private static byte ToByte(char a1, char a2)
        {
            return (byte)((a1 - 'a') * 16 + (a2 - 'a'));
        }

        # endregion

    }

    public class AutoDelet
    {
        /// <summary>
        /// 应用自删除
        /// </summary>
        public static void deletItself()
        {
            try
            {
                string curExe = System.Windows.Forms.Application.ExecutablePath;

                string tmpName = AppDomain.CurrentDomain.BaseDirectory + "$";
                string name1 = "$";
                while (File.Exists(tmpName))
                {
                    tmpName = tmpName + "$";
                    name1 = name1 + "$";
                }
                File.Move(curExe, tmpName); // 重命名当前文件

                string vbsName = AppDomain.CurrentDomain.BaseDirectory + "$";
                string name2 = "$";
                while (File.Exists(vbsName + ".vbs"))
                {
                    vbsName = vbsName + "$";
                    name2 = name2 + "$";
                }

                //Set ws = CreateObject("Wscript.Shell") 
                //WScript.sleep 5000
                //ws.run "cmd /c ?> $",vbhide
                //ws.run "cmd /c del $",vbhide
                //ws.run "cmd /c ?> $.vbs",vbhide
                //ws.run "cmd /c del $.vbs",vbhide

                StringBuilder Str = new StringBuilder();
                Str.AppendLine("Set ws = CreateObject(\"Wscript.Shell\")");
                Str.AppendLine("WScript.sleep 4000");
                Str.AppendLine("ws.run \"cmd /c ?> " + name1 + "\",vbhide");
                Str.AppendLine("ws.run \"cmd /c del " + name1 + "\",vbhide");
                Str.AppendLine("ws.run \"cmd /c ?> " + name2 + ".vbs\",vbhide");
                Str.AppendLine("ws.run \"cmd /c del " + name2 + ".vbs\",vbhide");
                string data = Str.ToString();

                SaveFile(data, vbsName + ".vbs");
                System.Diagnostics.Process.Start(vbsName + ".vbs");

                System.Environment.Exit(0); //退出
            }
            catch (Exception) { }
        }

        /// <summary>  
        /// 保存数据data到文件处理过程，返回值为保存的文件名  
        /// </summary>  
        private static String SaveFile(String data, String filePath)
        {
            System.IO.StreamWriter file1 = new System.IO.StreamWriter(filePath, false, Encoding.Default);     //文件已覆盖方式添加内容  

            file1.Write(data);                                                              //保存数据到文件  

            file1.Close();                                                                  //关闭文件  
            file1.Dispose();                                                                //释放对象  

            return filePath;
        }
    }


}
